package net.nohaven.proj.javeau.ui;

import java.awt.Color;
import java.awt.Point;
import java.io.File;

import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;

import net.nohaven.proj.javeau.fs.FSUtils;
import net.nohaven.proj.javeau.fs.crypt.CFSFactory;
import net.nohaven.proj.javeau.fs.exceptions.ConditionsNotMetException;
import net.nohaven.proj.javeau.fs.exceptions.EntityAlreadyPresentException;
import net.nohaven.proj.javeau.fs.exceptions.EntityNotFoundException;
import net.nohaven.proj.javeau.fs.hybrid.HFilesystem;
import net.nohaven.proj.javeau.fs.model.FSDirectory;
import net.nohaven.proj.javeau.ui.fw.GenericCompanion;
import net.nohaven.proj.javeau.ui.fw.LeftClickListener;
import net.nohaven.proj.javeau.ui.fw.MenuItemClickListener;
import net.nohaven.proj.javeau.ui.fw.PopupListener;
import net.nohaven.proj.javeau.ui.generated.FSPanel;
import net.nohaven.proj.javeau.utils.Utils;

public class FSPanelCompanion extends GenericCompanion {
	private static final Icon COPY_R_ICO = new ImageIcon(FSTableManager.class
			.getResource("icon/copyR.png"));
	private static final Icon COPY_L_ICO = new ImageIcon(FSTableManager.class
			.getResource("icon/copyL.png"));
	private static final Icon MOVE_R_ICO = new ImageIcon(FSTableManager.class
			.getResource("icon/moveR.png"));
	private static final Icon MOVE_L_ICO = new ImageIcon(FSTableManager.class
			.getResource("icon/moveL.png"));

	private static final Color HLIGHT_SEC_FS = new Color(255, 229, 141);

	public FSPanel gui;
	public FileManagerCompanion parent;

	private HFilesystem filesystem;
	private int position;

	private FSTableManager fsTableManager;

	public FSPanelCompanion(FileManagerCompanion fManager, int whichOne) {
		this.parent = fManager;
		gui = new FSPanel();

		gui.tfPwd.setBackground(Color.WHITE);

		switch (whichOne) {
		case FileManagerCompanion.LEFT_FS:
			gui.miCopy.setIcon(COPY_R_ICO);
			gui.miMove.setIcon(MOVE_R_ICO);
			break;
		case FileManagerCompanion.RIGHT_FS:
			gui.miCopy.setIcon(COPY_L_ICO);
			gui.miMove.setIcon(MOVE_L_ICO);
			break;
		}

		PopupListener ppl = new PopupListener(gui.jpPanel);
		gui.tblContents.addMouseListener(ppl);
		gui.spTableBackground.addMouseListener(ppl);

		ListSelectionListener selListener = new ListSelectionListener() {
			public void valueChanged(ListSelectionEvent e) {
				enablePopupItems();
			}
		};
		gui.tblContents.getSelectionModel().addListSelectionListener(
				selListener);

		gui.tblContents.addMouseListener(new LeftClickListener(2) {
			public void action(int x, int y, int clicks, int button) {
				int row = gui.tblContents.rowAtPoint(new Point(x, y));

				String cdTo = (String) gui.tblContents.getValueAt(row, 0);

				if (cdTo != null)
					try {
						filesystem.cd(cdTo);
						doOpsAssociatedToCd();
					} catch (EntityNotFoundException e) {
					}
			}
		});

		filesystem = new HFilesystem(this);
		fsTableManager = new FSTableManager(filesystem, this);

		this.position = whichOne;

		refreshDirView();

		gui.btRefresh.addMouseListener(new LeftClickListener() {
			public void action(int x, int y, int clicks, int button) {
				refreshDirView();
			}
		});

		gui.btParent.addMouseListener(new LeftClickListener() {
			public void action(int x, int y, int clicks, int button) {
				filesystem.cdUp();
				doOpsAssociatedToCd();
			}
		});

		gui.btRoot.addMouseListener(new LeftClickListener() {
			public void action(int x, int y, int clicks, int button) {
				filesystem.goToRoot();
				doOpsAssociatedToCd();
			}
		});

		//popup menu items
		gui.miRemove.addActionListener(new MenuItemClickListener() {
			public void action() {
				String[] names = getSelectedItems();

				if (names.length == 0)
					return;

				String msg;
				if (names.length == 1)
					msg = "Are you sure you want to delete \"" + names[0]
							+ "\"?";
				else
					msg = "Are you sure you want to delete " + names.length
							+ " items?";

				if (!askConfirmation(parent.gui, msg))
					return;

				try {
					for (String name : names)
						if (!Utils.isEmpty(name) && !"..".equals(name))
							FSUtils.deleteRecursive(
									FSPanelCompanion.this.filesystem, name);
				} catch (ConditionsNotMetException e) {
					reportError(parent.gui, e.getMessage());
				} finally {
					clearThis();
					refreshDirView();
				}
			}
		});

		gui.miCopy.addActionListener(new MenuItemClickListener() {
			public void action() {
				String[] names = getSelectedItems();

				if (names.length == 0)
					return;

				try {
					for (String name : names)
						if (!Utils.isEmpty(name) && !"..".equals(name))
							FSUtils.copyRecursive(filesystem, parent
									.getOtherPanel(position).filesystem, name);
				} catch (Exception e) {
					reportError(parent.gui, e.getMessage());
				} finally {
					clearOther();
					refreshDirView();
				}
			}
		});

		gui.miMove.addActionListener(new MenuItemClickListener() {
			public void action() {
				String[] names = getSelectedItems();

				if (names.length == 0)
					return;

				try {
					for (String name : names)
						if (!Utils.isEmpty(name) && !"..".equals(name))
							FSUtils.move(filesystem, parent
									.getOtherPanel(position).filesystem, name);
				} catch (Exception e) {
					reportError(parent.gui, e.getMessage());
				} finally {
					clearOther();
					refreshDirView();
				}
			}
		});

		gui.miNewFolder.addActionListener(new MenuItemClickListener() {
			public void action() {
				String name = askText(parent.gui, "New directory name:");
				if (Utils.isEmpty(name))
					return;

				try {
					filesystem.mkDir(name);
				} catch (EntityAlreadyPresentException e) {
					reportError(parent.gui, e.getMessage());
				}

				refreshDirView();
			}
		});

		gui.miNewSecureFolder.addActionListener(new MenuItemClickListener() {

			public void action() {
				String name = askText(parent.gui, "New secure folder name:");
				char[] pwd = askPassword(parent.gui);
				if (Utils.isEmpty(name) || Utils.isEmpty(pwd))
					return;

				try {
					filesystem.mkDir(name);

					//FIXME CFSFactory should be based on the RFSDir, 
					//      not a pure java File
					new CFSFactory(new File(
							((FSDirectory) filesystem.get(name)).getPath()),
							pwd).getInstance(false);

					filesystem.cd(name, pwd);
					doOpsAssociatedToCd();
				} catch (Exception e) {
					reportError(parent.gui, e.getMessage());
				}

				refreshDirView();
			}
		});

		gui.miRename.addActionListener(new MenuItemClickListener() {

			public void action() {
				String[] names = getSelectedItems();

				if (names.length != 1) {
					reportError(parent.gui, "Only one item should be selected");
					return;
				}

				String name = names[0];
				String newName = askText(parent.gui, "New name:", name);

				if (Utils.isEmpty(newName))
					return;

				try {
					filesystem.rename(name, newName);
				} catch (EntityNotFoundException e) {
					reportError(parent.gui, e.getMessage());
				} catch (EntityAlreadyPresentException e) {
					reportError(parent.gui, e.getMessage());
				}

				refreshDirView();
			}
		});
	}

	private void refreshDirView() {
		refreshDirViewSlave();

		//FIXME do this only if the other view is the same as this one
		if (parent.getOtherPanel(position) != null)
			parent.getOtherPanel(position).refreshDirViewSlave();
	}

	private void refreshDirViewSlave() {
		fsTableManager.calcView();
		gui.tblContents.updateUI();

		enablePopupItems();

		gui.tfPwd.setText(filesystem.getPwd().getPath());
	}

	public void dispose() {
		filesystem.close();
	}

	private String[] getSelectedItems() {
		return fsTableManager.getSelectedNames();
	}

	private boolean isAnyValidRowSelected() {
		//return if there is a selected row different than '..'
		int sr = gui.tblContents.getSelectedRowCount();
		if (sr == 0)
			return false;
		if (sr > 1)
			return true;
		return !"..".equals(fsTableManager.getSelectedNames()[0]);
	}

	private void enablePopupItems() {
		boolean rowsSel = isAnyValidRowSelected();
		boolean canWrite = filesystem.getPwd().canWrite();
		boolean isAlreadySecure = filesystem.isSecure();

		gui.miNewFolder.setEnabled(canWrite);
		gui.miNewSecureFolder.setEnabled(canWrite && !isAlreadySecure);

		gui.miRemove.setEnabled(rowsSel & canWrite);
		gui.miRename.setEnabled(rowsSel & canWrite);

		gui.miCopy.setEnabled(rowsSel & canWrite);
		gui.miMove.setEnabled(rowsSel & canWrite);
	}

	private void clearOther() {
		parent.getOtherPanel(position).clearThis();
	}

	private void clearThis() {
		gui.tblContents.clearSelection();
	}

	private void doOpsAssociatedToCd() {
		clearThis();
		refreshDirView();

		Color bg;
		if (filesystem.isSecure())
			bg = HLIGHT_SEC_FS;
		else
			bg = Color.WHITE;

		gui.tfPwd.setBackground(bg);
	}

	public char[] askPassword() {
		return askPassword(parent.gui);
	}

	public void reportError(String msg) {
		reportError(parent.gui, msg);
	}
}
